package com.yb.guigu.pick.activity.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yb.guigu.pick.activity.bean.*;
import com.yb.guigu.pick.activity.service.IRedPackageRainService;
import com.yb.guigu.pick.activity.util.SplitRedPackageUtil;
import com.yb.guigu.pick.core.bean.GuiguResult;
import com.yb.guigu.pick.core.constant.GuiguStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Copyright (C), 2022-2023, 姚兵
 * Author: 32210
 * Date: 2023/7/15 14:45
 * FileName: RedPackageRainServiceImpl
 * Description:
 */

@Service
@Slf4j
public class RedPackageRainServiceImpl implements IRedPackageRainService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    String READ_PACKAGE_KEY="activity:%s";

    // user:activity:{活动唯一标志}:{userId}
    String USER_READ_PACKAGE_KEY="user:activity:%s:%s";

    @Autowired
    ObjectMapper mvcObjectMapper;

    @Override
    public GuiguResult generate(BigDecimal totalMoney, int totalCount) {


        BigDecimal[] bigDecimals = SplitRedPackageUtil.splitRedPackageAlgorithm(totalMoney, totalCount);

        ArrayList<RedPackage> list = new ArrayList<>();


        BigDecimal splitTotalMoney = Arrays.stream(bigDecimals).reduce(BigDecimal.ZERO, BigDecimal::add);

        log.info("totalMoney:{}, splitTotalMoney:{}",totalMoney,splitTotalMoney);

        Assert.isTrue( totalMoney.compareTo(splitTotalMoney)==0,"总金额和分割金额不一致");;

        for (BigDecimal bigDecimal : bigDecimals) {

            RedPackage redPackage = new RedPackage();
            redPackage.setAmount(bigDecimal);
            redPackage.setUnit("yuan");

            String uuid = UUID.randomUUID().toString().replace("-", "");

            redPackage.setUuid(uuid);
            list.add(redPackage);
        }


        String activityId  = UUID.randomUUID().toString().replace("-", "");

        List<String> stringList = list.stream().map(item-> {
            try {
                return mvcObjectMapper.writeValueAsString(item);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());

        stringRedisTemplate.opsForList().rightPushAll(String.format(READ_PACKAGE_KEY,activityId),stringList);

        RedPackageRain redPackageRain = new RedPackageRain();
        redPackageRain.setId(activityId);
        redPackageRain.setName("红包雨");
        redPackageRain.setCount(totalCount);
        redPackageRain.setAmount(totalMoney);
        return GuiguResult.success(redPackageRain);
    }

    @Override
    public GuiguResult start(Integer userId, String redPackageId, Integer clickCount) throws JsonProcessingException {
        String key = String.format(READ_PACKAGE_KEY, redPackageId);

        RedPackageRainResult redPackageRainResult = new RedPackageRainResult();
        redPackageRainResult.setId(redPackageId);
        redPackageRainResult.setUserId(userId);
        redPackageRainResult.setCount(clickCount);
        if(clickCount<=0){

            return GuiguResult.success(redPackageRainResult).msg("很遗憾，没有抢到红包！");
        }

        BigDecimal amount=new BigDecimal(0);

        for (int i = 0; i < clickCount; i++) {

            String str = stringRedisTemplate.opsForList().leftPop(key);

            if(!StringUtils.hasLength(str)){
                break;
            }
            RedPackage redPackage= mvcObjectMapper.readValue(str,RedPackage.class);
            amount=amount.add(redPackage.getAmount());
        }


        amount=amount.setScale(2, RoundingMode.HALF_UP);
        redPackageRainResult.setAmount(amount);
        if(amount.compareTo(BigDecimal.ZERO)==0){
            return GuiguResult.success(redPackageRainResult).msg("很遗憾，没有抢到红包");
        }


        return GuiguResult.success(redPackageRainResult).msg("恭喜你，抽中了!~");
    }

    @Override
    public GuiguResult robRedPackage(String userId, String redPackageRainKey) {
        String key = String.format(READ_PACKAGE_KEY, redPackageRainKey);
        String str = stringRedisTemplate.opsForList().leftPop(key);

        if(!StringUtils.hasText(str)){
            return GuiguResult.error(GuiguStatus.BusinessStatus.RED_PACKAGE_GONE);
        }

        RedPackage redPackage;

        try {
            redPackage = mvcObjectMapper.readValue(str,RedPackage.class);
            String userKey=String.format(USER_READ_PACKAGE_KEY,redPackageRainKey,userId);
            stringRedisTemplate.opsForList().rightPush(userKey, mvcObjectMapper.writeValueAsString(redPackage));
            log.info("用户抢到红包 activity:{} userId:{} money:{}",redPackageRainKey,userId,redPackage.getAmount());
            UserRobRedPackageResult userRobRedPackageResult = new UserRobRedPackageResult();
            userRobRedPackageResult.setUserId(userId);
            userRobRedPackageResult.setId(redPackageRainKey);
            userRobRedPackageResult.setRedPackage(redPackage);
            return GuiguResult.success(userRobRedPackageResult);
        } catch (JsonProcessingException e) {
            log.error("{}",e);
            return GuiguResult.error();
        }
    }

    @Override
    public GuiguResult userRedPackageRecord(String userId, String redPackageRainKey) {

        UserRobRedPackageRecordResult userRobRedPackageRecordResult=new UserRobRedPackageRecordResult();

        String userKey=String.format(USER_READ_PACKAGE_KEY,redPackageRainKey,userId);


        List<String> stringList = stringRedisTemplate.opsForList().range(userKey, 0, -1);

        userRobRedPackageRecordResult.setId(redPackageRainKey);
        userRobRedPackageRecordResult.setUserId(userId);

        if(CollectionUtils.isEmpty(stringList)){
            return GuiguResult.success(userRobRedPackageRecordResult);
        }

        try {

            List<RedPackage> redPackages = stringList.stream().map(item -> {
                try {
                    return mvcObjectMapper.readValue(item, RedPackage.class);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }).collect(Collectors.toList());

            BigDecimal reduce = redPackages.stream().reduce(BigDecimal.ZERO, (one, other) -> one.add(other.getAmount()), BigDecimal::add);
            userRobRedPackageRecordResult.setTotalAmount(reduce);
            userRobRedPackageRecordResult.setCount(redPackages.size());
            return GuiguResult.success(userRobRedPackageRecordResult);
        }catch (Exception e){
            log.error("{}",e);
            return GuiguResult.error();
        }
    }
}
